﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SCMS.Model;
using System.Transactions;
using System.ComponentModel.DataAnnotations;

namespace SCMS.CoreBusinessLogic.PaymentVoucher
{
    public class PaymentVoucherService : IPaymentVoucherService
    {
        public bool IsPaymentVoucherSaved(Model.PaymentVoucher entity, List<RFPBLView> PVItems)
        {
            using (var dbContext = new SCMSEntities())
            {
                using (TransactionScope scope = new TransactionScope())
                {
                    try
                    {
                        dbContext.PaymentVouchers.AddObject(entity);
                        foreach (RFPBLView item in PVItems)
                        {
                            var newEntity = new PaymentVoucherBudgetLine()
                            {
                                Id = Guid.NewGuid(),
                                PaymentVoucherId = entity.Id,
                                PaymentRequestItemId = item.RFPItemId,
                                Description = item.Description,
                                GeneralLedgerId = (Guid)item.GLId,
                                Amount = item.amunt,
                            };
                            dbContext.PaymentVoucherBudgetLines.AddObject(newEntity);
                        }
                        if ((dbContext.SaveChanges() > 0))
                        {
                            //NotificationServiceMail.SendNotification(NotificationServiceMail.GetApproverEmailAddress(1, NotifcationHelper.spmCode), NotifcationHelper.spMsgBody, NotifcationHelper.spsubject);
                            scope.Complete(); return true;
                        }
                        else { scope.Dispose(); return false; }
                    }
                    catch (Exception ex) { scope.Dispose(); throw ex; }
                }
            }
        }

        public bool IsPaymentVoucherUpdated(Model.PaymentVoucher entity, List<RFPBLView> PVItems)
        {
            using (var dbContext = new SCMSEntities())
            {
                using (TransactionScope scope = new TransactionScope())
                {
                    try
                    {
                        dbContext.PaymentVouchers.Attach(entity);
                        dbContext.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Modified);
                        foreach (RFPBLView item in PVItems)
                        {
                            var pvit = dbContext.PaymentVoucherBudgetLines.FirstOrDefault(p => p.Id == item.Id);
                            pvit.Description = item.Description;
                            pvit.GeneralLedgerId = (Guid)item.GLId;
                            dbContext.ObjectStateManager.ChangeObjectState(pvit, System.Data.EntityState.Modified);
                        }
                        if ((dbContext.SaveChanges() > 0))
                        {
                            scope.Complete(); return true;
                        }
                        else { scope.Dispose(); return false; }
                    }
                    catch (Exception ex) { scope.Dispose(); throw ex; }
                }
            }
        }

        public bool IsPaymentVoucherDeleted(Guid PVId)
        {
            using (var db = new SCMSEntities())
            {
                db.PaymentVouchers.DeleteObject(db.PaymentVouchers.FirstOrDefault(p => p.Id == PVId));
                return db.SaveChanges() > 0 ? true : false;
            }
        }

        public string GenerateUniquNumber(Model.CountryProgramme cp)
        {
            string code = "PV/DRC/" + cp.Country.ShortName + "/";
            string refNumber = "";
            long count = 1;
            using (var dbContext = new SCMSEntities())
            {
                var total = dbContext.PaymentVouchers.Where(p => p.CountryProgrammeId == cp.Id && p.IsSubmitted == true).Count();
                count = total;
                Model.PaymentVoucher m = null;
                do
                {
                    count++;
                    if (count < 10000)
                    {
                        if (count < 10)
                            refNumber = code + "0000" + count;
                        if (count < 100 & count >= 10)
                            refNumber = code + "000" + count;
                        if (count < 1000 & count >= 100)
                            refNumber = code + "00" + count;
                        if (count < 10000 & count >= 1000)
                            refNumber = code + "0" + count;
                    }
                    m = dbContext.PaymentVouchers.FirstOrDefault(p => p.RefNumber == refNumber);
                } while (m != null);
                return refNumber;
            }
        }

        public List<RFPBLView> GetRFPItemsDetails(Guid RFPId)
        {
            using (var dbContext = new SCMSEntities())
            {
                var mm = dbContext.PaymentRequests.IncludePurchaseOrder().IncludePurchaseOrderItems().IncludeOrderRequestItems().ToList();
                List<RFPBLView> poitemList = new List<RFPBLView>();
                poitemList = (from rfp in dbContext.PaymentRequests
                              join rfpitmz in dbContext.PaymentRequestBudgetLines on rfp.Id equals rfpitmz.PaymentRequestId
                              join pb in dbContext.ProjectBudgets on rfpitmz.BudgetLineId equals pb.Id
                              join poItz in dbContext.PurchaseOrderItems on rfpitmz.PurchaseOrderItemId equals poItz.Id
                              join orItz in dbContext.OrderRequestItems on poItz.OrderRequestItemId equals orItz.Id
                              where rfp.Id == RFPId
                              select new RFPBLView
                              {
                                  RFPItemId = rfpitmz.Id,
                                  BLine = pb.LineNumber,
                                  Description = orItz.ItemDescription,
                                  LineDescription = pb.Description,
                                  amunt = (float)rfpitmz.Amount,
                                  GLId = pb.GeneralLedgerId,
                                  glCodes = dbContext.GeneralLedgers.Where(p => p.MasterBudgetCategory.CountryProgrammeId == rfp.CountryProgrammeId)
                              }).ToList<RFPBLView>();
                return poitemList;
            }
        }

        public List<RFPBLView> GetPVItemsDetails(Guid PVId)
        {
            using (var dbContext = new SCMSEntities())
            {
                var mm = dbContext.PaymentRequests.IncludePurchaseOrder().IncludePurchaseOrderItems().IncludeOrderRequestItems().ToList();
                List<RFPBLView> poitemList = new List<RFPBLView>();
                poitemList = (from pvitmz in dbContext.PaymentVoucherBudgetLines
                              join pb in dbContext.ProjectBudgets on pvitmz.PaymentRequestBudgetLine.ProjectBudget.Id equals pb.Id
                              where pvitmz.PaymentVoucherId == PVId
                              select new RFPBLView
                              {
                                  Id = pvitmz.Id,
                                  RFPItemId = pvitmz.PaymentRequestItemId,
                                  BLine = pb.LineNumber,
                                  Description = pvitmz.Description,
                                  LineDescription = pb.Description,
                                  amunt = (float)pvitmz.Amount,
                                  GLId = pvitmz.GeneralLedgerId,
                                  glCodes = dbContext.GeneralLedgers.Where(p => p.MasterBudgetCategory.CountryProgrammeId == pvitmz.PaymentVoucher.CountryProgrammeId)
                              }).ToList<RFPBLView>();
                return poitemList;
            }
        }

        public List<Model.PaymentVoucher> GetPaymentVouchers(Guid cpId)
        {
            using (var db = new SCMSEntities())
            {
                return db.PaymentVouchers
                    .IncludePurchaseOrder()
                    .Where(p => p.CountryProgrammeId == cpId).OrderByDescending(p => p.PreparedOn).ToList();

                //foreach (var item in db.PaymentVouchers.Where(p => p.CountryProgrammeId == cpId).ToList())
                //{

                //    foreach (var itemu in item.PaymentVoucherBudgetLines)
                //    {
                //        itemu.GeneralLedger.PaymentRequestBudgetLine.ProjectBudget
                //    }
                //}
            }
        }

        public Model.PaymentVoucher GetPaymentVoucherById(Guid PVId)
        {
            using (var db = new SCMSEntities())
            {
                var PV = db.PaymentVouchers
                    .IncludePaymentRequestBudgetLines()
                    .IncludePurchaseOrder()
                    .IncludePaymentType()
                    .IncludeSupplier()
                    .IncludeGeneralLedger()
                    .FirstOrDefault(p => p.Id == PVId);

                PV.AmountInWords = NumberConversion.NumWordsWrapper((double)PV.PaymentVoucherBudgetLines.Sum(p => p.Amount)).ToTitleCase();
                PV.PreparedByStaff = db.VStaffDetails.FirstOrDefault(p => p.StaffID == PV.PreparedBy);
                PV.AuthourisedByStaff = db.VStaffDetails.FirstOrDefault(p => p.StaffID == PV.AuthorizedBy);
                PV.CanEdit = true;
                return PV;
            }
        }
    }

    public class RFPBLView
    {
        public Guid Id { get; set; }
        public string BLine { get; set; }
        public string LineDescription { get; set; }
        [Required]
        public string Description { get; set; }
        public float amunt { get; set; }
        [Required]
        public Guid? GLId { get; set; }
        public Guid RFPItemId { get; set; }
        public IEnumerable<Model.GeneralLedger> glCodes { get; set; }
    }

    public class NumberConversion
    {
        public static String NumWordsWrapper(double n)
        {
            string words = "";
            double intPart;
            double decPart = 0;
            if (n == 0)
                return "zero";
            try
            {
                string[] splitter = n.ToString().Split('.');
                intPart = double.Parse(splitter[0]);
                decPart = double.Parse(splitter[1]);
            }
            catch
            {
                intPart = n;
            }

            words = NumWords(intPart);

            if (decPart > 0)
            {
                if (words != "")
                    words += " and ";
                int counter = decPart.ToString().Length;
                switch (counter)
                {
                    case 1: words += NumWords(decPart) + " tenths"; break;
                    case 2: words += NumWords(decPart) + " hundredths"; break;
                    case 3: words += NumWords(decPart) + " thousandths"; break;
                    case 4: words += NumWords(decPart) + " ten-thousandths"; break;
                    case 5: words += NumWords(decPart) + " hundred-thousandths"; break;
                    case 6: words += NumWords(decPart) + " millionths"; break;
                    case 7: words += NumWords(decPart) + " ten-millionths"; break;
                }
            }
            return words;
        }

        static String NumWords(double n) //converts double to words
        {
            string[] numbersArr = new string[] { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
            string[] tensArr = new string[] { "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninty" };
            string[] suffixesArr = new string[] { "thousand", "million", "billion", "trillion", "quadrillion", "quintillion", "sextillion", "septillion", "octillion", "nonillion", "decillion", "undecillion", "duodecillion", "tredecillion", "Quattuordecillion", "Quindecillion", "Sexdecillion", "Septdecillion", "Octodecillion", "Novemdecillion", "Vigintillion" };
            string words = "";

            bool tens = false;

            if (n < 0)
            {
                words += "negative ";
                n *= -1;
            }

            int power = (suffixesArr.Length + 1) * 3;

            while (power > 3)
            {
                double pow = Math.Pow(10, power);
                if (n > pow)
                {
                    if (n % Math.Pow(10, power) > 0)
                    {
                        words += NumWords(Math.Floor(n / pow)) + " " + suffixesArr[(power / 3) - 1] + ", ";
                    }
                    else if (n % pow > 0)
                    {
                        words += NumWords(Math.Floor(n / pow)) + " " + suffixesArr[(power / 3) - 1];
                    }
                    n %= pow;
                }
                power -= 3;
            }
            if (n >= 1000)
            {
                if (n % 1000 > 0) words += NumWords(Math.Floor(n / 1000)) + " thousand, ";
                else words += NumWords(Math.Floor(n / 1000)) + " thousand";
                n %= 1000;
            }
            if (0 <= n && n <= 999)
            {
                if ((int)n / 100 > 0)
                {
                    words += NumWords(Math.Floor(n / 100)) + " hundred";
                    n %= 100;
                }
                if ((int)n / 10 > 1)
                {
                    if (words != "")
                        words += " ";
                    words += tensArr[(int)n / 10 - 2];
                    tens = true;
                    n %= 10;
                }

                if (n < 20 && n > 0)
                {
                    if (words != "" && tens == false)
                        words += " ";
                    words += (tens ? "-" + numbersArr[(int)n - 1] : numbersArr[(int)n - 1]);
                    n -= Math.Floor(n);
                }
            }

            return words;

        }
    }
}
